﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Geometry {
    public class BBox {
        public Point pMin, pMax;

        public BBox() {
            pMin = new Point(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
            pMax = new Point(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
        }
        public BBox(Point p) {
            pMin = new Point(p);
            pMax = new Point(p);
        }
        public BBox(Point p, Point q) {
            pMin = new Point(
                Math.Min(p.x, q.x),
                Math.Min(p.y, q.y),
                Math.Min(p.z, q.z));
            pMax = new Point(
                Math.Max(p.x, q.x),
                Math.Max(p.y, q.y),
                Math.Max(p.z, q.z));
        }

        public static BBox union(BBox b, Point p) {
            BBox ret = new BBox();

            ret.pMin.x = Math.Min(b.pMin.x, p.x);
            ret.pMin.y = Math.Min(b.pMin.y, p.y);
            ret.pMin.z = Math.Min(b.pMin.z, p.z);

            ret.pMax.x = Math.Max(b.pMax.x, p.x);
            ret.pMax.y = Math.Max(b.pMax.y, p.y);
            ret.pMax.z = Math.Max(b.pMax.z, p.z);

            return ret;
        }

        public bool overlaps(BBox b) {
            bool fx = (pMin.x <= b.pMax.x) && (b.pMin.x <= pMax.x);
            bool fy = (pMin.y <= b.pMax.y) && (b.pMin.y <= pMax.y);
            bool fz = (pMin.z <= b.pMax.z) && (b.pMin.z <= pMax.z);
            return fx && fy && fz;
        }

        public bool inside(Point p) {
            return (pMin.x <= p.x && p.x <= pMax.x
                && pMin.y <= p.y && p.y <= pMax.y
                && pMin.z <= p.z && p.z <= pMax.z);
        }

        public void Expand(float delta) {
            Vector vd = new Vector(delta, delta, delta);
            pMin -= vd;
            pMax += vd;
        }

        public float volume() {
            Vector d = pMax - pMin;
            return d.x * d.y * d.z;
        }

        public int maximumExtent() {
            Vector d = pMax - pMin;
            if (d.y < d.x && d.z < d.x)
                return 0;
            if (d.z < d.y)
                return 1;
            return 2;
        }

        public void bindingSphere(out Point c, float rad) {
            c = 0.5f * (pMin + pMax);
            rad = c.distance(pMax);
        }
    }
}
